﻿using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace Gmantis.Controls.DataGrid
{
    [TemplatePart(Name = "FilterButton", Type = typeof(Button)), 
    TemplatePart(Name = "InnerControlContainer", Type = typeof(ContentControl)), 
    TemplatePart(Name = "ClearButton", Type = typeof(Button))]
    public class DataGridFilter : Control, IDataGridFilter
    {
        // Fields
        internal Button _elementClearButton;
        internal Button _elementFilterButton;
        internal ContentControl _elementInnerControlContainer;
        private IDataGridFilter _innerControl;
        internal bool _isLoaded;
        internal const string ClearButtonElementName = "ClearButton";
        internal const string FilterButtonElementName = "FilterButton";
        public static readonly DependencyProperty FocusBrushProperty = DependencyProperty.Register("FocusBrush", typeof(Brush), typeof(DataGridFilter), null);
        internal const string InnerControlContainerElementName = "InnerControlContainer";
        private const string InnerControlNotSetMsg = "InnerControl not set.";
        public static readonly DependencyProperty MouseOverBrushProperty = DependencyProperty.Register("MouseOverBrush", typeof(Brush), typeof(DataGridFilter), null);
        public static readonly DependencyProperty PressedBrushProperty = DependencyProperty.Register("PressedBrush", typeof(Brush), typeof(DataGridFilter), null);

        // Events
        public event EventHandler<PropertyChangedEventArgs<DataGridFilterState>> FilterChanged;

        // Methods
        public DataGridFilter()
        {
            base.DefaultStyleKey = typeof(DataGridFilter);
            this.SetCustomDefaultValues();
        }

        public void Clear()
        {
            if (this._innerControl == null)
            {
                throw new Exception("InnerControl not set.");
            }
            this._innerControl.Clear();
        }

        public void Create()
        {
            if (this._innerControl == null)
            {
                throw new Exception("InnerControl not set.");
            }
            this._innerControl.Create();
        }

        private T GetTemplateChild<T>(string childName, bool required, ref string errors) where T : class
        {
            DependencyObject templateChild = base.GetTemplateChild(childName);
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "template part", childName, templateChild, required, ref errors);
            return (templateChild as T);
        }

        private static Storyboard GetTemplateChildResource(FrameworkElement root, string resourceName, bool required, ref string errors)
        {
            return GetTemplateChildResource<Storyboard>(root, resourceName, required, ref errors);
        }

        private static T GetTemplateChildResource<T>(FrameworkElement root, string resourceName, bool required, ref string errors) where T : class
        {
            object child = root.Resources[resourceName];
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "resource", resourceName, child, required, ref errors);
            return (child as T);
        }

        public void Load(DataGridFilterState filterState)
        {
            if (this._innerControl == null)
            {
                throw new Exception("InnerControl not set.");
            }
            this._innerControl.Load(filterState);
        }

        private void OnAfterApplyTemplate()
        {
            this._elementFilterButton.Click += (s, e) => this.Create();
            this._elementClearButton.Click += (s, e) => this.Clear();
            this._elementInnerControlContainer.Content = this._innerControl;
            if (this._innerControl != null)
            {
                this._innerControl.FilterChanged += new EventHandler<PropertyChangedEventArgs<DataGridFilterState>>(this.OnFilterChanged);
            }
        }

        public override void OnApplyTemplate()
        {
            this.OnBeforeApplyTemplate();
            string errors = string.Empty;
            base.OnApplyTemplate();
            this._isLoaded = true;
            this._elementInnerControlContainer = this.GetTemplateChild<ContentControl>("InnerControlContainer", true, ref errors);
            this._elementFilterButton = this.GetTemplateChild<Button>("FilterButton", true, ref errors);
            this._elementClearButton = this.GetTemplateChild<Button>("ClearButton", true, ref errors);
            if (!string.IsNullOrEmpty(errors))
            {
                this._isLoaded = false;
                if ((base.Template != null) && !PlatformIndependent.IsInDesignMode(this))
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Template cannot be applied to DataGridFilter.\nDetails: {0}", new object[] { errors }));
                }
            }
            else
            {
                this.OnAfterApplyTemplate();
            }
        }

        private void OnBeforeApplyTemplate()
        {
            if (this._elementInnerControlContainer != null)
            {
                this._elementInnerControlContainer.Content = null;
            }
        }

        private void OnFilterChanged(object sender, PropertyChangedEventArgs<DataGridFilterState> e)
        {
            if (this.FilterChanged != null)
            {
                this.FilterChanged(this, e);
            }
        }

        private void SetCustomDefaultValues()
        {
        }

        // Properties
        public Brush FocusBrush
        {
            get
            {
                return (Brush)base.GetValue(FocusBrushProperty);
            }
            set
            {
                base.SetValue(FocusBrushProperty, value);
            }
        }

        public IDataGridFilter InnerControl
        {
            get
            {
                return this._innerControl;
            }
            set
            {
                this._innerControl = value;
            }
        }

        public Brush MouseOverBrush
        {
            get
            {
                return (Brush)base.GetValue(MouseOverBrushProperty);
            }
            set
            {
                base.SetValue(MouseOverBrushProperty, value);
            }
        }

        public Brush PressedBrush
        {
            get
            {
                return (Brush)base.GetValue(PressedBrushProperty);
            }
            set
            {
                base.SetValue(PressedBrushProperty, value);
            }
        }
    }
}
